package com.tiancheng.trade.payment.channel.umsshop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.tiancheng.commom.pay.PayOrderAutoQueryConfig;
import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.commom.core.enums.ClearingCycleModeEnum;
import com.tiancheng.trade.commom.core.enums.PaySceneEnum;
import com.tiancheng.trade.commom.core.enums.PaymentChannelEnum;
import com.tiancheng.trade.commom.core.enums.PaymentWayEnum;
import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.commom.core.utils.JsonUtil;
import com.tiancheng.trade.commom.web.cache.model.MerchantBO;
import com.tiancheng.trade.commom.web.model.request.MerchantChannelRequestDTO;
import com.tiancheng.trade.commom.web.model.response.SettlementRuleResVO;
import com.tiancheng.trade.commom.core.utils.DateTimeUtil;
import com.tiancheng.trade.payment.channel.AbstractPayChannel;
import com.tiancheng.trade.payment.channel.bo.*;
import com.tiancheng.trade.payment.channel.bo.paybo.AlipayResBO;
import com.tiancheng.trade.payment.channel.bo.paybo.OutUrlPayResBO;
import com.tiancheng.trade.payment.channel.bo.paybo.UnionMiniPayResBO;
import com.tiancheng.trade.payment.channel.bo.paybo.WechatPayResBO;
import com.tiancheng.trade.payment.channel.enums.ChannelOrderStatusEnum;
import com.tiancheng.trade.payment.channel.enums.UmsOrderStatusEnum;
import com.tiancheng.trade.payment.channel.enums.UmsRefundStatusEnum;
import com.tiancheng.trade.payment.channel.ums.params.UmsUnifiedOrderParam;
import com.tiancheng.trade.payment.channel.umsshop.request.*;
import com.tiancheng.trade.payment.channel.umsshop.response.*;
import com.tiancheng.trade.payment.channel.umsshop.util.UmsShopHttpUtils;
import com.tiancheng.trade.payment.enums.ChannelRefundTypeEnum;
import com.tiancheng.trade.payment.mapper.PaymentFlowDetailMapper;
import com.tiancheng.trade.payment.mapper.PaymentOrderMapper;
import com.tiancheng.trade.payment.mapper.PaymentRefundFlowMapper;
import com.tiancheng.trade.payment.model.*;
import com.tiancheng.trade.payment.service.SettlePlatformService;
import com.tiancheng.trade.payment.util.CommonUtil;
import com.tiancheng.trade.payment.util.ObjectConvertUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 银联新购物车支付渠道
 */
@Slf4j
@Service
public class UmsShopPayChannel implements AbstractPayChannel {
    @Resource
    private UmsShopAllConfig umsShopAllConfig;
    @Resource
    private PaymentFlowDetailMapper paymentFlowDetailMapper;
    @Resource
    private PaymentRefundFlowMapper paymentRefundFlowMapper;
    @Resource
    private SettlePlatformService settlePlatformService;
    @Resource
    private PaymentOrderMapper paymentOrderMapper;


    @Override
    public PaymentChannelEnum getPaymentChannelEnum() {
        return PaymentChannelEnum.UMS_SHOP;
    }

    /**
     * 银联商务统一下单
     *
     * @param unifiedOrderBO {@link UnifiedOrderBO}
     * @return {@link Result<UnifiedOrderResBO>}
     * @throws BusinessException
     */
    @Override
    public Result<UnifiedOrderResBO> unifiedOrder(UnifiedOrderBO unifiedOrderBO) throws BusinessException {
        UmsShopUnifiedOrderRequest unifiedOrderRequest = new UmsShopUnifiedOrderRequest();
        unifiedOrderRequest.setSysSource("OPT");
        unifiedOrderRequest.setMchntOrderId(unifiedOrderBO.getFlowId());
        final UmsShopProperties umsShopProperties = umsShopAllConfig.getByOrgPayChannelId(unifiedOrderBO.getOrgPaymentChannelId());

        handlePayWay(unifiedOrderRequest, unifiedOrderBO, umsShopProperties); // 不同支付方式处理
        // 支付有效时间
        LocalDateTime payExpiryTime = Objects.nonNull(unifiedOrderBO.getPayExpiryTime()) ? unifiedOrderBO.getPayExpiryTime() : LocalDateTime.now();
        unifiedOrderRequest.setExpireTime(DateTimeUtil.temporalFormat2String(payExpiryTime, "yyyy-MM-dd HH:mm:ss"));
        unifiedOrderRequest.setOrderDesc(CommonUtil.orderNameHandle(unifiedOrderBO.getOrderName()));
        // 子订单商品信息-商品维度清分
        List<UmsShopGoodsReq> goods = new ArrayList<>();
        List<UnifiedOrderResBO.SubOrder> subOrders = new ArrayList<>();
        unifiedOrderBO.getSubOrders().forEach(subOrderBO -> {
            UmsShopGoodsReq umsProduct = new UmsShopGoodsReq();
            umsProduct.setGoodsId(subOrderBO.getProductCode());
            // TODO 微信、支付宝支付需要限制商品id不超过32位
            umsProduct.setGoodsId(CommonUtil.subString(subOrderBO.getProductCode(), 32));
            umsProduct.setGoodsName(CommonUtil.orderNameHandle(subOrderBO.getProductName()));
            umsProduct.setQuantity(subOrderBO.getProductCount());
            umsProduct.setPrice(subOrderBO.getAmount()); // 传实付金额
            //umsProduct.setSubMerchantId(subOrderBO.getSubMerchantId());
            //umsProduct.setMerOrderId(subOrderBO.getSubFlowId());
            //umsProduct.setSubOrderAmount(subOrderBO.getAmount());
            goods.add(umsProduct);
            UnifiedOrderResBO.SubOrder subOrder = ObjectConvertUtil.convert(umsProduct, UnifiedOrderResBO.SubOrder.class).get();
            subOrder.setEnterpriseCode(subOrderBO.getEnterpriseCode());
            subOrder.setSubOrderId(subOrderBO.getSubOrderId());
            subOrders.add(subOrder);
        });

        // 分账信息
        UmsShopPaySettlReq settlReq = genShopSettle(unifiedOrderBO);
        unifiedOrderRequest.setVaFld(settlReq);
        unifiedOrderRequest.setGoods(goods);
        // 商品标记，用于优惠活动(微信)
        unifiedOrderRequest.setGoodsTag(unifiedOrderBO.getGoodsTag());

        Optional.ofNullable(unifiedOrderBO.getAmount()).ifPresent(unifiedOrderRequest::setOriginalAmount);

        Assert.isTrue(null != unifiedOrderBO.getAmount(), "订单支付总金额有误");
        unifiedOrderRequest.setTotalAmount(unifiedOrderBO.getAmount());
        // TODO 分账方案确认
        unifiedOrderRequest.setNotifyUrl(umsShopProperties.getPayCallback());
        final String umsMopUrl = getUmsShopUrl(unifiedOrderBO.getPayScene(), unifiedOrderBO.getPayWay());
        //umsUnifiedOrderParam.setSign(buildSignString(umsMopProperties.getKey(), umsUnifiedOrderParam));
        log.info("ums_mop_unifiedOrder_url:{}, params:{}", umsMopUrl, JsonUtil.toJsonString(unifiedOrderRequest));
        Result<UnifiedOrderResBO> result = new Result<>();

        try {
            final UmpShopUnifiedResponse response = new UmsShopHttpUtils<UmpShopUnifiedResponse>(umsShopProperties,
                    umsMopUrl).doPostToken(JsonUtil.toJsonString(unifiedOrderRequest), UmpShopUnifiedResponse.class);
            log.info("银联shop统一下单返回:{}", JsonUtil.toJsonString(response));
            // 处理相响应结果
            result.setRet(response.isOK() ? 0 : 1);
            result.setMsg(response.getRespDesc());

            UnifiedOrderResBO unifiedOrderResBO = new UnifiedOrderResBO();
            unifiedOrderResBO.setTransactionId(response.getSeqId() == null ? "" : response.getSeqId());
            unifiedOrderResBO.setOutTradeNo(response.getTargetOrderId() == null ? "" : response.getTargetOrderId());
            unifiedOrderResBO.setSubOrders(subOrders);

            // 微信小程序
            if (PaySceneEnum.MINIAPP.getCode().equalsIgnoreCase(unifiedOrderBO.getPayScene())) {
                if (PaymentWayEnum.WECHAT.getCode().equalsIgnoreCase(unifiedOrderBO.getPayWay())) {
                    // 微信小程序
                    ;
                    unifiedOrderResBO.setPayInfo(JsonUtil.toJsonString(JsonUtil.fromJson(response.getMiniPayRequest(), WechatPayResBO.class)));
                } else if (PaymentWayEnum.ALIPAY.getCode().equalsIgnoreCase(unifiedOrderBO.getPayWay())) {
                    // 支付宝小程序
                    unifiedOrderResBO.setPayInfo(JsonUtil.toJsonString(JsonUtil.fromJson(response.getMiniPayRequest(), AlipayResBO.class)));
                } else if (PaymentWayEnum.UNIONPAY.getCode().equalsIgnoreCase(unifiedOrderBO.getPayWay())) {
                    // 云闪付小程序
                    unifiedOrderResBO.setPayInfo(JsonUtil.toJsonString(JsonUtil.fromJson(response.getMiniPayRequest(), UnionMiniPayResBO.class)));
                }
                result.setData(unifiedOrderResBO);
                return result;
            } else if (PaySceneEnum.PCWEB.getCode().equalsIgnoreCase(unifiedOrderBO.getPayScene())) {
                OutUrlPayResBO outUrlPayResBO = new OutUrlPayResBO();
                outUrlPayResBO.setPayUrl(response.getBillQRCode());
                unifiedOrderResBO.setPayInfo(JsonUtil.toJsonString(outUrlPayResBO));
                result.setData(unifiedOrderResBO);
                return result;
            }
            result.setData(unifiedOrderResBO);
        } catch (Exception e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("下单支付失败");
        }
        return result;
    }

    /**
     * 生成结算信息
     *
     * @param unifiedOrderBO
     * @return
     */
    private UmsShopPaySettlReq genShopSettle(UnifiedOrderBO unifiedOrderBO) {
        UmsShopPaySettlReq settlReq = new UmsShopPaySettlReq();
        settlReq.setNewShopFlag("GWCXS");
        settlReq.setIsSubMchntPay("01");
        // 平台分账金额
        //settlReq.setPlatAmt(unifiedOrderBO.getSubSettles().stream().mapToInt(UnifiedOrderSettleBO::getPlatformAmount).sum());
        // 同步分账
        settlReq.setSatType("01");
        List<UmsShopPaySettlItemReq> items = new ArrayList<>();
        for (UnifiedOrderSettleBO subSettle : unifiedOrderBO.getSubSettles()) {
            for (UnifiedOrderSettleBO.UnifiedOrderSettleItemBO settleItem : subSettle.getSettleItems()) {
                UmsShopPaySettlItemReq item = new UmsShopPaySettlItemReq();
                item.setMerId(settleItem.getMid());
                item.setMerOrderId(settleItem.getMerOrderId());
                item.setSatAmt(settleItem.getTotalAmount().toString());
                item.setOrderDesc(settleItem.getIsPlatformMerchant() ? "平台分账所得" : "子商户分账所得");
                if (!PaySceneEnum.PCWEB.getCode().equalsIgnoreCase(unifiedOrderBO.getPayScene()) && !PaymentWayEnum.SCAN.getCode().equals(unifiedOrderBO.getPayWay())) {
                    item.setSubsidyAmt(0);
                }
                items.add(item);
            }
        }
        settlReq.setSatInfo(items);
        return settlReq;
    }

    /**
     * 下单查询
     *
     * @param getUnifiedOrderBO {@link GetUnifiedOrderBO}
     * @return {@link Result<GetUnifiedOrderResBO>}
     * @throws BusinessException
     */
    @Override
    public Result<GetUnifiedOrderResBO> get(GetUnifiedOrderBO getUnifiedOrderBO) throws BusinessException {
        final UmsShopProperties umsMopProperties = umsShopAllConfig.getByOrgPayChannelId(getUnifiedOrderBO.getOrgPaymentChannelId());
        UmsShopGetOrderReq umsGetUnifiedOrderParam = new UmsShopGetOrderReq();

        QueryWrapper<PaymentOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flow_id", getUnifiedOrderBO.getOrderId());
        queryWrapper.eq("user_id", getUnifiedOrderBO.getUid());
        PaymentOrder paymentOrder = paymentOrderMapper.selectOne(queryWrapper);
        Assert.isTrue(null != paymentOrder, "未查询到相应流水");
        Assert.isTrue(!StringUtils.isEmpty(paymentOrder.getPaymentWay()), "流水支付方式异常");

        Map<String, String> mtiMap = handleMidTidInstMid(paymentOrder.getPayScene(), paymentOrder.getPaymentWay(), umsMopProperties);
        umsGetUnifiedOrderParam.setSysSource("OPT");
        umsGetUnifiedOrderParam.setVaMchntNo(mtiMap.get("mid"));
        umsGetUnifiedOrderParam.setVaTermNo(mtiMap.get("tid"));
        if (paymentOrder.getPayScene().equals(PaySceneEnum.PCWEB.getCode())) {
            umsGetUnifiedOrderParam.setMchntOrderId(getUnifiedOrderBO.getOrderId());
            umsGetUnifiedOrderParam.setBillNo(getUnifiedOrderBO.getOrderId());
            umsGetUnifiedOrderParam.setBillDate(DateTimeUtil.formatter(paymentOrder.getCreateTime(), "yyyy-MM-dd"));
        } else {
            umsGetUnifiedOrderParam.setMchntOrderId(getUnifiedOrderBO.getOrderId());
        }
        umsGetUnifiedOrderParam.setSysSource(umsMopProperties.getSysSource());

        String url = "v1/inip/upsp/shop/mini/pay-query";
        if (PaySceneEnum.PCWEB.getCode().equalsIgnoreCase(paymentOrder.getPayScene())) {
            url = "v1/inip/upsp/shop/csb/query";
        }

        log.info("ums_shop_getUnifiedOrder_url:{}, params:{}", umsMopProperties.getApiUrl(), JsonUtil.toJsonString(umsGetUnifiedOrderParam));
        Result<GetUnifiedOrderResBO> result = new Result<>();
        try {
            final UmsShopGetUnifiedOrderResponse getResult = new UmsShopHttpUtils<UmsShopGetUnifiedOrderResponse>(umsMopProperties,
                    url).doPostToken(JsonUtil.toJsonString(umsGetUnifiedOrderParam), UmsShopGetUnifiedOrderResponse.class);

            log.info("银联支付查询返回:{}", JsonUtil.toJsonString(getResult));
            // 处理相响应结果
            // 处理响应结果
            result.setRet(getResult.isOK() ? 0 : 1);
            result.setMsg(StringUtils.isNotEmpty(getResult.getRespDesc()) ? getResult.getRespDesc() : "");
            GetUnifiedOrderResBO getUnifiedOrderResBO = new GetUnifiedOrderResBO();
            getUnifiedOrderResBO.setOrderId(getResult.getMerOrderId());
            getUnifiedOrderResBO.setTransactionId(getResult.getSeqId());
            getUnifiedOrderResBO.setTradeNo(getResult.getTargetOrderId());


            String channelPayStatus = getResult.getStatus();
            Integer channelPayInvoiceAmount = getResult.getInvoiceAmount();
            String payTime = getResult.getPayTime();
            if (PaySceneEnum.PCWEB.getCode().equalsIgnoreCase(paymentOrder.getPayScene())) {
                // C扫B查询返回
                UmsShopGetUnifiedOrderResponse.UmsShopBillPayment billPayment = getResult.getBillPayment();
                channelPayStatus = billPayment.getStatus();
                channelPayInvoiceAmount = billPayment.getBuyerPayAmount();
                payTime = billPayment.getPayTime();
                getUnifiedOrderResBO.setOrderId(billPayment.getMerOrderId());
            }

            // 订单状态处理
            switch (UmsOrderStatusEnum.getByCode(channelPayStatus)) {
                case NEW_ORDER:
                case WAIT_BUYER_PAY:
                    getUnifiedOrderResBO.setOrderStatus(ChannelOrderStatusEnum.wait);
                    break;
                case UNKNOWN:
                case TRADE_CLOSED:
                case TRADE_REFUND:
                    getUnifiedOrderResBO.setOrderStatus(ChannelOrderStatusEnum.fail);
                    break;
                case TRADE_SUCCESS:
                    getUnifiedOrderResBO.setOrderStatus(ChannelOrderStatusEnum.success);
                    break;
                default:
                    getUnifiedOrderResBO.setOrderStatus(ChannelOrderStatusEnum.fail);
            }
            if (StringUtils.isNotEmpty(payTime)) {
                getUnifiedOrderResBO.setPayTime(DateTimeUtil.string2LocalDateTime(payTime, "yyyy-MM-dd HH:mm:ss"));
            }
            if (null != channelPayInvoiceAmount) {
                getUnifiedOrderResBO.setAmount(channelPayInvoiceAmount);
            } else if (null != getResult.getTotalAmount()) {
                getUnifiedOrderResBO.setAmount(getResult.getTotalAmount());
            }

            result.setData(getUnifiedOrderResBO);
        } catch (Exception e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("查询订单失败");
        }
        return result;
    }

    /**
     * 退款
     *
     * @param refundOrderBO {@link RefundOrderBO}
     * @return {@link Result<RefundOrderResBO>}
     * @throws BusinessException
     */
    @Override
    public Result<RefundOrderResBO> refund(RefundOrderBO refundOrderBO) throws BusinessException {
        UmsShopRefundReq umsRefundOrderParam = new UmsShopRefundReq();
        final UmsShopProperties umsShopProperties = umsShopAllConfig.getByOrgPayChannelId(refundOrderBO.getOrgPaymentChannelId());

        QueryWrapper<PaymentOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flow_id", refundOrderBO.getOrderId());
        queryWrapper.eq("user_id", refundOrderBO.getUid());
        PaymentOrder paymentOrder = paymentOrderMapper.selectOne(queryWrapper);

        Assert.isTrue(null != paymentOrder, "未查询到相应流水");
        Assert.isTrue(!StringUtils.isEmpty(paymentOrder.getPaymentWay()), "流水支付方式异常");

        Map<String, String> mtiMap = handleMidTidInstMid(paymentOrder.getPayScene(), paymentOrder.getPaymentWay(), umsShopProperties);
        umsRefundOrderParam.setSysSource("OPT");
        umsRefundOrderParam.setVaMchntNo(mtiMap.get("mid"));
        umsRefundOrderParam.setVaTermNo(mtiMap.get("tid"));
        if (paymentOrder.getPayScene().equals(PaySceneEnum.PCWEB.getCode())) {
            umsRefundOrderParam.setBillNo(refundOrderBO.getOrderId());
            umsRefundOrderParam.setBillDate(DateTimeUtil.formatter(paymentOrder.getCreateTime(), "yyyy-MM-dd"));
        } else {
            umsRefundOrderParam.setMchntOrderId(refundOrderBO.getOrderId());
        }
        umsRefundOrderParam.setTargetOrderId(paymentOrder.getFlowId());

        Assert.isTrue(null != refundOrderBO.getAmount() && null != refundOrderBO.getOrderAmount(), "退款金额异常");
        Set<String> subOrderIds = refundOrderBO.getSubOrders().stream().map(RefundOrderBO.SubOrderBO::getSubOrderId).collect(Collectors.toSet());
        QueryWrapper<PaymentFlowDetail> conditions = new QueryWrapper<>();
        conditions.eq("flow_id", refundOrderBO.getOrderId()).in("sub_order_id", subOrderIds);
        List<PaymentFlowDetail> flowDetails = paymentFlowDetailMapper.selectList(conditions);

        // 子订单流水 key=subOrderId, value=subOrderFlowId
        Map<String, String> subFlowIdMap = new HashMap<>();
        // 商户进件号处理相关-1
        List<MerchantChannelRequestDTO> merchantChannelRequestDTOS = new ArrayList<>();
        for (PaymentFlowDetail flowDetail : flowDetails) {
            subFlowIdMap.put(flowDetail.getSubOrderId(), flowDetail.getSubFlowId());
            merchantChannelRequestDTOS.add(new MerchantChannelRequestDTO(flowDetail.getMerchantCode(), refundOrderBO.getPaymentChannelCode(), refundOrderBO.getOrgPaymentChannelId(), refundOrderBO.getBusinessCode()));
        }
        // 商户进件号处理相关-2
        Map<String, MerchantBO> merchantMap = settlePlatformService.getMerchantInfo(merchantChannelRequestDTOS);// key=merchantCode, value=商户进件号
        Map<String, String> subMerchantMap = new HashMap<>(); // key=subOrderId, value=商户进件号
        // 商户进件号处理相关-3、清分规则处理相关-3
        for (PaymentFlowDetail detail : flowDetails) {
            subMerchantMap.put(detail.getSubOrderId(), merchantMap.get(detail.getMerchantCode()).getSubAppid());
        }
        // 提高垃圾回收效率
        flowDetails.clear();
        flowDetails = null;
        merchantChannelRequestDTOS.clear();
        merchantChannelRequestDTOS = null;
        merchantMap.clear();
        merchantMap = null;

        String refundUrl = "v1/inip/upsp/shop/mini/refund";
        if (PaySceneEnum.PCWEB.getCode().equalsIgnoreCase(paymentOrder.getPayScene())) {
            refundUrl = "v1/inip/upsp/shop/csb/refund";
        }

        Result<RefundOrderResBO> result = refundWithSubOrders(umsRefundOrderParam, refundOrderBO, umsShopProperties, refundUrl);
        log.info("部分退款，部分多个子订单退款-同步退款。");
        RefundOrderResBO refundOrderResBO = new RefundOrderResBO();
        // 延迟退款处理，实退金额返回0
        refundOrderResBO.setRefundTypeEnum(ChannelRefundTypeEnum.ALL);
        result.setData(refundOrderResBO);
        return result;

    }

    /**
     * 退款查询
     *
     * @param getRefundOrderBO {@link GetRefundOrderBO}
     * @return {@link Result<GetRefundOrderResBO>}
     * @throws BusinessException
     */
    @Override
    public Result<GetRefundOrderResBO> getRefund(GetRefundOrderBO getRefundOrderBO) throws BusinessException {
        UmsShopGetRefundReq umsShopGetRefundReq = new UmsShopGetRefundReq();
        final UmsShopProperties umsShopProperties = umsShopAllConfig.getByOrgPayChannelId(getRefundOrderBO.getOrgPaymentChannelId());

        QueryWrapper<PaymentRefundFlow> conditions = new QueryWrapper<>();
        conditions.eq("user_id", getRefundOrderBO.getUid());
        conditions.eq("flow_id", getRefundOrderBO.getRefundId());
        PaymentRefundFlow refundFlow = paymentRefundFlowMapper.selectOne(conditions);
        Assert.isTrue(null != refundFlow, "未查询到相应退款流水");

        QueryWrapper<PaymentOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flow_id", refundFlow.getPayFlowId());
        queryWrapper.eq("user_id", getRefundOrderBO.getUid());
        PaymentOrder paymentOrder = paymentOrderMapper.selectOne(queryWrapper);
        Assert.isTrue(null != paymentOrder, "未查询到相应支付流水");
        Assert.isTrue(!StringUtils.isEmpty(paymentOrder.getPaymentWay()), "流水支付方式异常");

        Map<String, String> mtiMap = handleMidTidInstMid(paymentOrder.getPayScene(), paymentOrder.getPaymentWay(), umsShopProperties);
        umsShopGetRefundReq.setSysSource("OPT");
        umsShopGetRefundReq.setVaMchntNo(mtiMap.get("mid"));
        umsShopGetRefundReq.setVaTermNo(mtiMap.get("tid"));

        if (paymentOrder.getPayScene().equals(PaySceneEnum.PCWEB.getCode())) {
            umsShopGetRefundReq.setBillNo(paymentOrder.getFlowId());
            umsShopGetRefundReq.setRefundOrderId(getRefundOrderBO.getRefundId());
            umsShopGetRefundReq.setBillDate(DateTimeUtil.formatter(paymentOrder.getCreateTime(), "yyyy-MM-dd"));
        } else {
            umsShopGetRefundReq.setMchntOrderId(getRefundOrderBO.getRefundId());
        }


        String refundQueryUrl = "v1/inip/upsp/shop/mini/refund-query";
        if (PaySceneEnum.PCWEB.getCode().equalsIgnoreCase(paymentOrder.getPayScene())) {
            refundQueryUrl = "v1/inip/upsp/shop/csb/query";
        }
        log.info("ums_shop_getRefund_url:{}, params:{}", umsShopProperties.getApiUrl(), JsonUtil.toJsonString(umsShopGetRefundReq));
        Result<GetRefundOrderResBO> result = new Result<>();
        try {
            final UmsShopGetRefundOrderResponse refundOrderResult = new UmsShopHttpUtils<UmsShopGetRefundOrderResponse>(umsShopProperties, refundQueryUrl).doPostToken(JsonUtil.toJsonString(umsShopGetRefundReq), UmsShopGetRefundOrderResponse.class);
            log.info("银联shop退款查询返回:{}", JsonUtil.toJsonString(refundOrderResult));

            result.setRet(refundOrderResult.isOK() ? 0 : 1);
            result.setMsg(refundOrderResult.getRespDesc());
            GetRefundOrderResBO resBO = new GetRefundOrderResBO();
            resBO.setRefundId(refundOrderResult.getRefundOrderId());
            resBO.setTransactionId(refundOrderResult.getSeqId());
            resBO.setTradeNo(refundOrderResult.getTargetOrderId());
            // 退款时间，银联未返回，使用退款流水表中退款时间
            resBO.setRefundTime(refundFlow.getFlowTime());

            // 退款状态
            resBO.setChannelOrderStatusEnum(ChannelOrderStatusEnum.ing);
            String channelRefundStatus = refundOrderResult.getRefundStatus();
            Integer refundInvoiceAmount = refundOrderResult.getRefundInvoiceAmount();
            if (PaySceneEnum.PCWEB.getCode().equalsIgnoreCase(paymentOrder.getPayScene())) {
                // C扫B查询返回
                UmsShopGetRefundOrderResponse.UmsShopRefundBillPayment refundBillPayment = refundOrderResult.getRefundBillPayment();
                channelRefundStatus = refundBillPayment.getStatus();
                refundInvoiceAmount = refundBillPayment.getInvoiceAmount();
            }
            switch (UmsRefundStatusEnum.getByValue(channelRefundStatus)) {
                case PROCESSING:
                    resBO.setChannelOrderStatusEnum(ChannelOrderStatusEnum.ing);
                    break;
                case FAIL:
                case UNKNOWN:
                    resBO.setChannelOrderStatusEnum(ChannelOrderStatusEnum.fail);
                    break;
                case SUCCESS:
                    resBO.setChannelOrderStatusEnum(ChannelOrderStatusEnum.success);
                    break;
            }
            resBO.setAmount(refundInvoiceAmount);
            result.setData(resBO);
        } catch (Exception e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("查询退款失败");
        }
        return result;
    }

    /**
     * 关闭订单
     *
     * @param closeOrderBO {@link CloseOrderBO}
     * @return {@link Result}
     * @throws BusinessException
     */
    @Override
    public Result<?> close(CloseOrderBO closeOrderBO) throws BusinessException {

        UmsShopCloseOrderReq umsShopCloseOrderParam = new UmsShopCloseOrderReq();
        final UmsShopProperties umsShopProperties = umsShopAllConfig.getByOrgPayChannelId(closeOrderBO.getOrgPaymentChannelId());
        umsShopCloseOrderParam.setRequestTimestamp(DateTimeUtil.temporalFormat2String(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));

        QueryWrapper<PaymentOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flow_id", closeOrderBO.getOrderId());
        queryWrapper.eq("user_id", closeOrderBO.getUid());
        PaymentOrder paymentOrder = paymentOrderMapper.selectOne(queryWrapper);
        Assert.isTrue(null != paymentOrder, "未查询到相应支付流水");
        Assert.isTrue(!StringUtils.isEmpty(paymentOrder.getPaymentWay()), "流水支付方式异常");

        Map<String, String> mtiMap = handleMidTidInstMid(paymentOrder.getPayScene(), paymentOrder.getPaymentWay(), umsShopProperties);
        umsShopCloseOrderParam.setSysSource("OPT");
        umsShopCloseOrderParam.setVaMchntNo(mtiMap.get("mid"));
        umsShopCloseOrderParam.setVaTermNo(mtiMap.get("tid"));
        umsShopCloseOrderParam.setInstMid(mtiMap.get("instMid"));
        String closeUrl = "v1/inip/upsp/shop/common/order-close";
        if (paymentOrder.getPayScene().equals(PaySceneEnum.PCWEB.getCode())) {
            closeUrl = "v1/inip/upsp/shop/csb/close-qrcode";
            umsShopCloseOrderParam.setBillNo(closeOrderBO.getOrderId());
            umsShopCloseOrderParam.setBillDate(DateTimeUtil.formatter(paymentOrder.getCreateTime(), "yyyy-MM-dd"));
        } else {
            umsShopCloseOrderParam.setMchntOrderId(closeOrderBO.getOrderId());
        }
        log.info("ums_mop_close_url:{}, params:{}", umsShopProperties.getApiUrl(), JsonUtil.toJsonString(umsShopCloseOrderParam));
        Result<?> result = new Result<>();
        try {
            final UmpShopCloseOrderRes closeOrderResult = new UmsShopHttpUtils<UmsShopGetRefundOrderResponse>(umsShopProperties, closeUrl).doPostToken(JsonUtil.toJsonString(umsShopCloseOrderParam), UmpShopCloseOrderRes.class);
            log.info("银联shop关闭订单返回:{}", JsonUtil.toJsonString(closeOrderResult));

            result.setRet(closeOrderResult.isOK() ? 0 : 1);
            result.setMsg(closeOrderResult.getRespDesc());
        } catch (Exception e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("关闭订单失败");
        }
        result.setMsg("银联商务新购物车关闭订单成功");
        return result;
    }

    /**
     * 处理支付结果
     *
     * @param payResult {@link Map}
     * @return {@link PayResultBO}
     */
    @Override
    public PayResultBO payResult(Map<String, Object> payResult) {
        //  消息验证sign
//        this.callbackMsgCheck(payResult);
        BusinessErrorInfoEnum.UMS_CHANNEL_SIGN_FAIL.assertIsTrue(this.callbackMsgCheck(payResult));
        PayResultBO payResultBO = new PayResultBO();
        //TODO 待确认订单状态，是否需要再次发起查询
        BusinessErrorInfoEnum.CHANNEL_CALLBACK_PAY_UNKNOWN_STATUS.assertIsTrue((payResult.containsKey("status") && payResult.get("status").toString().equalsIgnoreCase("TRADE_SUCCESS")) ||
                (payResult.get("billStatus").toString().equalsIgnoreCase("PAID")));
        payResultBO.setStatus("success");
        //payResultBO.setUid(String.valueOf(payResult.get("buyerId")));
        if (payResult.containsKey("merOrderId")) {
            payResultBO.setOrderId(String.valueOf(payResult.get("merOrderId")));
        } else if (payResult.containsKey("billNo")) {
            payResultBO.setOrderId(String.valueOf(payResult.get("billNo")));
        }
        LocalDateTime payTime = LocalDateTime.now();
        if (payResult.containsKey("targetOrderId")) {
            payResultBO.setTransactionId(String.valueOf(payResult.get("targetOrderId")));
            // 处理优惠金额
            // 总金额
            int totalAmount = Integer.parseInt(String.valueOf(payResult.get("totalAmount")));
            int couponAmount = 0;
            // 实付金额
            if (payResult.containsKey("buyerPayAmount") && !StringUtils.isEmpty(MapUtils.getString(payResult, "buyerPayAmount"))) {
                int buyerPayAmount = Integer.parseInt(payResult.get("buyerPayAmount").toString());
                if (buyerPayAmount > 0) {
                    couponAmount = totalAmount - buyerPayAmount;
                }
            }
            // 实际支付金额
            payResultBO.setAmount(totalAmount - couponAmount);
            // 优惠金额
            payResultBO.setCouponAmount(couponAmount);
            payResultBO.setMetadata(String.valueOf(payResult.get("attachedData")));
            if (payResult.containsKey("payTime") && payResult.get("payTime") != null) {
                payTime = DateTimeUtil.string2LocalDateTime(payResult.get("payTime").toString(), "yyyy-MM-dd HH:mm:ss");
            }

        } else if (payResult.containsKey("billPayment") && payResult.get("billPayment") != null) {
            JSONObject billPaymentJson = JSON.parseObject(payResult.get("billPayment").toString());
            payResultBO.setTransactionId(billPaymentJson.getString("targetOrderId"));
            //buyerCashPayAmt,云闪付会返回这个字段
            // 总金额
            Integer totalAmount = billPaymentJson.getInteger("totalAmount");
            int couponAmount = 0;
            // 实付金额
            if (billPaymentJson.containsKey("buyerCashPayAmt") && !StringUtils.isEmpty(billPaymentJson.getString("buyerCashPayAmt"))) {
                Integer buyerCashPayAmt = Integer.valueOf(billPaymentJson.get("buyerCashPayAmt").toString());
                if (buyerCashPayAmt > 0) {
                    couponAmount = totalAmount - buyerCashPayAmt;
                }
            }
            // 实际支付金额
            payResultBO.setAmount(totalAmount - couponAmount);
            // 优惠金额
            payResultBO.setCouponAmount(couponAmount);
            payResultBO.setMetadata(billPaymentJson.getString("billDesc"));
            if (billPaymentJson.containsKey("payTime") && billPaymentJson.get("payTime") != null) {
                payTime = DateTimeUtil.string2LocalDateTime(billPaymentJson.getString("payTime"), "yyyy-MM-dd HH:mm:ss");
            }
        }
        payResultBO.setTradeNo(payResultBO.getOrderId());
        payResultBO.setPayTime(payTime);
        return payResultBO;
    }

    /**
     * 处理退款结果
     *
     * @param refundResult {@link Map}
     * @return {@link RefundResultBO}
     */
    @Override
    public RefundResultBO refundResult(Map<String, Object> refundResult) {
        try {
            //  消息验证sign
            BusinessErrorInfoEnum.UMS_CHANNEL_SIGN_FAIL.assertIsTrue(this.callbackMsgCheck(refundResult));
            // TODO 里面的退款单号
            RefundResultBO refundResultBO = new RefundResultBO();
            refundResultBO.setStatus("success");
            if (refundResult.containsKey("refundOrderId")) {
                refundResultBO.setRefundId(String.valueOf(refundResult.get("refundOrderId")));
            }

            refundResultBO.setTransactionId(String.valueOf(refundResult.get("seqId")));
            refundResultBO.setTradeNo(refundResult.containsKey("refundTargetOrderId") && refundResult.get("refundTargetOrderId") != null ? String.valueOf(refundResult.get("refundTargetOrderId")) : null);
            refundResultBO.setAmount(Integer.valueOf(String.valueOf(refundResult.get("refundAmount"))));

            LocalDateTime refundPayTime = LocalDateTime.now();
            if (refundResult.containsKey("refundPayTime") && refundResult.get("refundPayTime") != null) {
                refundPayTime = DateTimeUtil.string2LocalDateTime(refundResult.get("refundPayTime").toString(), "yyyy-MM-dd HH:mm:ss");
            }
            refundResultBO.setRefundTime(refundPayTime);
            return refundResultBO;
        } catch (Exception e) {
            throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_CALLBACK_REFUND_ERROR, null, e.getMessage(), e);
        }
    }

    @Override
    public Result settleV2(List<PaymentFlowDetailSettle> detailSettles, List<PaymentFlowDetailSettleDetail> detailSettlesDetails) throws BusinessException {
        if (CollectionUtils.isEmpty(detailSettles)) {
            return Result.fail("划账数据为空！");
        }
        return Result.success();
        /*final List<PaymentOrder> paymentOrderList = paymentOrderMapper.selectList(new LambdaQueryWrapper<PaymentOrder>().in(PaymentOrder::getFlowId, detailSettles.stream().map(PaymentFlowDetailSettle::getFlowId).collect(Collectors.toSet())));
        // 生成批次号
        // 结算批次号
        final String settleBatchNo = PaymentIdHelper.getSettleBatchNo(detailSettles.get(0).getOrgPaymentChannelId());
        try {
            // 根据流水号来分组，较少调用银商的次数
            final Map<String, List<PaymentFlowDetailSettle>> flowGroups = detailSettles.stream().collect(Collectors.groupingBy(PaymentFlowDetailSettle::getFlowId));
            flowGroups.forEach((flowId, flows) -> {
                final PaymentOrder paymentOrder = paymentOrderList.stream().filter(f -> f.getFlowId().equals(flowId)).findFirst().get();
                final UmsMopProperties umsMopProperties = umsShopAllConfig.getByOrgPayChannelId(paymentOrder.getOrgPaymentChannelId());
                final UmsMopSettleConfirmRequest request = new UmsMopSettleConfirmRequest();
                Map<String, String> mtiMap = handleMidTidInstMid(paymentOrder.getPayScene(), paymentOrder.getPaymentWay(), umsMopProperties);
                request.setRequestTimestamp(DateTimeUtil.temporalFormat2String(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
                request.setMid(mtiMap.get("mid"));
                request.setTid(mtiMap.get("tid"));
                request.setInstMid(mtiMap.get("instMid"));
                request.setMerOrderId(flowId);
                final int totalPlatformAmount = flows.stream().mapToInt(PaymentFlowDetailSettle::getPlatformAmount).sum();
                request.setPlatformAmount((long) totalPlatformAmount);

                final List<UmsMopSettleConfirmRequest.UmsMopSettleConfirmSubOrder> subOrders = new ArrayList<>();
                final UmsMopSettleConfirmRequest.UmsMopSettleConfirmSubOrder suborder = new UmsMopSettleConfirmRequest.UmsMopSettleConfirmSubOrder();
                final List<PaymentFlowDetailSettleDetail> details = detailSettlesDetails.stream().filter(d -> flows.stream().map(PaymentFlowDetailSettle::getSettleFlowId).collect(Collectors.toSet()).contains(d.getSettleFlowId())).toList();

                for (PaymentFlowDetailSettleDetail detail : details) {
                    // 子商户号
                    suborder.setMid(detail.getSubMerchantId());
                    suborder.setMerOrderId(detail.getSubFlowId());
                    suborder.setTotalAmount(detail.getAmount());
                    subOrders.add(suborder);
                }
                request.setSubOrders(subOrders);
                final UmsMopSettleConfirmResponse settleConfirmResult;
                try {
                    settleConfirmResult = new UmsMopHttpUtils<UmsMopSettleConfirmResponse>(umsMopProperties, "sub-orders-confirm")
                            .doPostToken(JsonUtil.toJsonString(request), UmsMopSettleConfirmResponse.class);
                    log.info("银联shop订单确认分账返回:{}", JsonUtil.toJsonString(settleConfirmResult));
                    if (!settleConfirmResult.isOK()) {
                        // TODO 失败处理
                        log.info("error");
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            return Result.success();
        } catch (Exception e) {
            throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_CALLBACK_REFUND_ERROR, null, e.getMessage(), e);
        }*/
    }

    @Override
    public boolean autoQueryStatus(Long orgPaymentChannelId) {
        final UmsShopProperties umsShopProperties = umsShopAllConfig.getByOrgPayChannelId(orgPaymentChannelId);
        return umsShopProperties.autoQueryStatus();
    }

    @Override
    public PayOrderAutoQueryConfig getOrderAutoQueryConfig(Long orgPaymentChannelId) {
        final UmsShopProperties umsShopProperties = umsShopAllConfig.getByOrgPayChannelId(orgPaymentChannelId);
        if (Objects.isNull(umsShopProperties) || Objects.isNull(umsShopProperties.getQueryStatusConfig())) {
            return null;
        }
        return umsShopProperties.getQueryStatusConfig();
    }

    /**
     * 各支付场景下各支付方式参数处理
     *
     * @param umsShopUnifiedOrderParam {@link UmsUnifiedOrderParam}
     * @param unifiedOrderBO           {@link UnifiedOrderBO}
     */
    private void handlePayWay(UmsShopUnifiedOrderRequest umsShopUnifiedOrderParam, UnifiedOrderBO unifiedOrderBO, UmsShopProperties properties) {
        umsShopUnifiedOrderParam.setVaMchntNo(properties.getVaMchntNo());
        umsShopUnifiedOrderParam.setVaTermNo(properties.getVaTermNo());
        umsShopUnifiedOrderParam.setSubAppId(unifiedOrderBO.getSubAppId());
        umsShopUnifiedOrderParam.setSubOpenId(unifiedOrderBO.getOpenid());
        // 1、app中支付
        if (PaySceneEnum.APP.getCode().equalsIgnoreCase(unifiedOrderBO.getPayScene())) {
            umsShopUnifiedOrderParam.setTradeType("APP");
        }

        // 2、微信小程序中支付 - 只支持微信支付方式
        if (PaySceneEnum.MINIAPP.getCode().equalsIgnoreCase(unifiedOrderBO.getPayScene())) {
            umsShopUnifiedOrderParam.setTradeType("MINI");
            umsShopUnifiedOrderParam.setInstMid("MINIDEFAULT");
            if (PaymentWayEnum.WECHAT.getCode().equals(unifiedOrderBO.getPayWay())) {
                umsShopUnifiedOrderParam.setMsgType("wx.unifiedOrder");
            } else if (PaymentWayEnum.ALIPAY.getCode().equals(unifiedOrderBO.getPayWay())) {
                umsShopUnifiedOrderParam.setMsgType("trade.create");
                umsShopUnifiedOrderParam.setUserId(unifiedOrderBO.getOpenid());
            } else if (PaymentWayEnum.UNIONPAY.getCode().equals(unifiedOrderBO.getPayWay())) {
                umsShopUnifiedOrderParam.setMsgType("uac.miniOrder");
            } else {
                BusinessErrorInfoEnum.SYSTEM_ERROR.assertFail("小程序场景不支持的支付方式" + unifiedOrderBO.getPayWay());
            }
        } else if (PaySceneEnum.PCWEB.getCode().equalsIgnoreCase(unifiedOrderBO.getPayScene())) {
            // pc端支付
            //umsShopUnifiedOrderParam.setMsgType("wx.unifiedOrder");
            umsShopUnifiedOrderParam.setMchntOrderId(null);
            umsShopUnifiedOrderParam.setSubAppId(null);
            umsShopUnifiedOrderParam.setSubOpenId(null);
            umsShopUnifiedOrderParam.setOrderDesc(null);
            umsShopUnifiedOrderParam.setQrCodeId(null);

            umsShopUnifiedOrderParam.setBillDesc(umsShopUnifiedOrderParam.getOrderDesc());
            umsShopUnifiedOrderParam.setBillNo(umsShopUnifiedOrderParam.getMchntOrderId());
            umsShopUnifiedOrderParam.setBillDate(DateTimeUtil.formatter(LocalDateTime.now(), "yyyy-MM-dd"));
            umsShopUnifiedOrderParam.setExpireTime(DateTimeUtil.temporalFormat2String(LocalDateTime.now().plusMinutes(30L), "yyyy-MM-dd HH:mm:ss")); // 二维码有效时间
        }

    }

    /**
     * 获取银商-新购物车请求url
     *
     * @param payScene
     * @param payWay
     * @return
     */
    private String getUmsShopUrl(String payScene, String payWay) {
        if (PaySceneEnum.APP.getCode().equals(payScene)) {
            // app支付
            return "v1/inip/upsp/shop/app/pay";
        } else if (PaySceneEnum.MINIAPP.getCode().equals(payScene)) {
            // 小程序支付
            return "v1/inip/upsp/shop/mini/pay";
        } else if (PaySceneEnum.H5.getCode().equals(payScene)) {
            // 小程序支付
            return "v1/inip/upsp/shop/h5/pay";
        } else if (PaySceneEnum.PCWEB.getCode().equals(payScene)) {
            return "v1/inip/upsp/shop/csb/get-qrcode";
        }
        return null;
    }

    /**
     * 根据支付下单场景和支付方式处理mid和tid
     *
     * @param payScene 支付场景
     * @param payWay   支付方式
     * @return {@link Map}
     */
    private Map<String, String> handleMidTidInstMid(String payScene, String payWay, UmsShopProperties umsShopProperties) {
        Map<String, String> map = new HashMap<>();
        map.put("mid", umsShopProperties.getVaMchntNo());
        map.put("tid", umsShopProperties.getVaTermNo());
        /*// 1、平台app中支付
        if (PaySceneEnum.APP.getCode().equalsIgnoreCase(payScene)) {
            // 微信
            if (PaymentWayEnum.WECHAT.getCode().equalsIgnoreCase(payWay)) {
                map.put("mid", umsShopProperties.getVaMchntNo());
                map.put("tid", umsShopProperties.getVaTermNo());
                return map;
            }

            map.put("mid", umsShopProperties.getMidApp());
            map.put("tid", umsShopProperties.getTidApp());
            map.put("instMid", umsShopProperties.getInstMidApp());
            return map;
        }

        // 2、微信小程序中支付
        if (PaySceneEnum.MINIAPP.getCode().equalsIgnoreCase(payScene)) {
            map.put("mid", umsShopProperties.getMidMini());
            map.put("tid", umsShopProperties.getTidMini());
            map.put("instMid", umsShopProperties.getInstMidMini());
            return map;
        }

        // 3、微信公众号h5中支付
        if (PaySceneEnum.WXAPP.getCode().equalsIgnoreCase(payScene)) {
            map.put("mid", umsShopProperties.getMidWxApp());
            map.put("tid", umsShopProperties.getTidWxApp());
            map.put("instMid", umsShopProperties.getInstMidWxApp());
            return map;
        }

        // 4、h5中支付
        if (PaySceneEnum.H5.getCode().equalsIgnoreCase(payScene)) {
            map.put("mid", umsShopProperties.getMidApp());
            map.put("tid", umsShopProperties.getTidApp());
            map.put("instMid", umsShopProperties.getInstMidH5());
            return map;
        }

        // 5、扫码支付
        if (PaySceneEnum.SCAN.getCode().equalsIgnoreCase(payScene)) {
            map.put("mid", umsShopProperties.getMidScan());
            map.put("tid", umsShopProperties.getTidScan());
            map.put("instMid", umsShopProperties.getInstMidScan());
            return map;
        }
        // 6、云闪付小程序
        if (PaySceneEnum.UNION_MINI.getCode().equalsIgnoreCase(payScene)) {
            map.put("mid", umsShopProperties.getMidMini());
            map.put("tid", umsShopProperties.getTidMini());
            map.put("instMid", umsShopProperties.getInstMidMini());
            return map;
        }*/
        return map;
    }

    /**
     * 根据清分规则计算渠道应核销日期
     *
     * @param settlementRuleResVO {@link SettlementRuleResVO} 清分规则
     * @param startDate           {@link LocalDate} 计算的基点日期
     * @return {@link LocalDate}
     */
    private LocalDate calSettleDate(SettlementRuleResVO settlementRuleResVO, LocalDate startDate) {
        LocalDate settleDate;
        // 清分周期类型-按天
        if (ClearingCycleModeEnum.DATE.getCode().equalsIgnoreCase(settlementRuleResVO.getClearingCycleMode())) {
            settleDate = startDate.plusDays(settlementRuleResVO.getClearingCycleValue());
        } else { // 清分周期类型-按月
            settleDate = startDate.plusMonths(settlementRuleResVO.getClearingCycleValue());
            settleDate = settleDate.withDayOfMonth(settlementRuleResVO.getClearingCycleValueExt());
        }
        return settleDate;
    }

    private boolean callbackMsgCheck(Map<String, Object> msg) {
        if (!msg.containsKey("sign") || StringUtils.isEmpty(MapUtils.getString(msg, "sign"))) {
            log.info("消息内容无sign字段");
            return false;
        }
        boolean checkResult = false;
        try {
            return true;
            /*String umsSign = msg.get("sign").toString();
            Optional<String> sign = buildSignString2(umsMopProperties.getKey(), msg);
            if (!sign.isPresent()) {
                log.info("银联消息验签失败");
                return false;
            }
            checkResult = org.apache.commons.lang3.StringUtils.equalsIgnoreCase(umsSign, sign.get());
            if (!checkResult) {
                log.error("银联消息验签失败");
            }*/
        } catch (Exception e) {
            log.error("银联消息验签失败:{}", e.getMessage());
            checkResult = false;
        }

        return checkResult;
    }


    /**
     * 2022-07-22 银联反馈不限制子订单部分退款，测试用
     * 一次退款，测试
     *
     * @param umsShopRefundReq 退款参数
     * @return
     */
    public Result<RefundOrderResBO> refundWithSubOrders(UmsShopRefundReq umsShopRefundReq, RefundOrderBO refundOrderBO,
                                                        UmsShopProperties umsShopProperties, String url) {
        BusinessErrorInfoEnum.CHANNEL_REFUND_FAIL_PARAMS_ERROR.assertIsTrue(umsShopRefundReq != null &&
                refundOrderBO != null);
        if (CollectionUtils.isEmpty(umsShopRefundReq.getGoods())) {
            umsShopRefundReq.setGoods(new ArrayList<>(refundOrderBO.getSubOrders().size()));
        }
        /*refundOrderBO.getSubOrders().forEach(s -> {
            final UmsShopGoodsReq goods = new UmsShopGoodsReq();
            UmsShopGoodsReq umsProduct = new UmsShopGoodsReq();
            umsProduct.setSubMerchantId(subMerchantMap.get(s.getSubOrderId()));
            umsProduct.setMerOrderId(subFlowIdMap.get(s.getSubOrderId()));
            umsProduct.setSubOrderAmount(s.getAmount() - s.getRefundPlatformDiscount());
            umsShopRefundReq.getGoods().add(umsProduct);
        });*/

        // 生成增值域的结算信息
        UmsShopRefundSettlReq settlReq = new UmsShopRefundSettlReq();
        settlReq.setNewShopFlag("GWCXS");
        settlReq.setIsSubMchntPay("01");
        settlReq.setSatType("01");
        // 结算明细处理
        int platAmt = 0;
        List<UmsShopRefundSettlItemReq> satInfo = new ArrayList<>();
        for (RefundOrderSettleBO settle : refundOrderBO.getSettles()) {
            for (RefundOrderSettleBO.RefundOrderSettleItemBO settleItem : settle.getSettleItems()) {
                UmsShopRefundSettlItemReq item = new UmsShopRefundSettlItemReq();
                item.setMerId(settleItem.getMid());
                item.setRefundOrderId(settleItem.getMerOrderId());
                item.setRefundAmt(settleItem.getTotalAmount().toString());
                item.setOriMerOrderId(settleItem.getOriMerOrderId());
                item.setOrderDesc("子商户退款分账返佣");
                item.setRemark("商户：" + settleItem.getMerchantRegId());
                item.setSubsidyAmt(0);
                satInfo.add(item);
            }
        }
        // 平台分账金额
        settlReq.setPlatAmt(platAmt);
        settlReq.setSatInfo(satInfo);
        umsShopRefundReq.setVaFld(settlReq);
        umsShopRefundReq.setRefundOrderId(refundOrderBO.getRefundId());
        umsShopRefundReq.setRefundAmount(String.valueOf(refundOrderBO.getAmount() - refundOrderBO.getRefundPlatformDiscount()));

        BusinessErrorInfoEnum.CHANNEL_REFUND_FAIL_AMOUNT_ERROR.assertIsTrue(Integer.parseInt(umsShopRefundReq.getRefundAmount()) == umsShopRefundReq.getVaFld().getSatInfo().stream().mapToInt(a -> Integer.parseInt(a.getRefundAmt())).sum());
        Result<RefundOrderResBO> result = this.doRefund(umsShopRefundReq, umsShopProperties, url);
        if (result.getRet() != 0) {
            log.error("退款失败:{}", result);
            return result;
        }
        if (result.getData() != null && result.getData().getRefundInvoiceAmount() != null) {
            // 实际退款的金额
            PaymentRefundFlow updateRefundFlow = new PaymentRefundFlow();
            updateRefundFlow.setAmount(result.getData().getRefundInvoiceAmount());
            updateRefundFlow.setRefundChannelDiscount(Integer.parseInt(umsShopRefundReq.getRefundAmount()) - result.getData().getRefundInvoiceAmount());
            QueryWrapper<PaymentRefundFlow> conditions = new QueryWrapper<>();
            conditions.eq("flow_id", umsShopRefundReq.getRefundOrderId());
            conditions.eq("user_id", refundOrderBO.getUid());
            paymentRefundFlowMapper.update(updateRefundFlow, conditions);
            result.getData().setRefundInvoiceAmount(0);// 设置实付金额=0，不再做更新
        }
        return result;
    }


    /**
     * 整单退款
     *
     * @param umsShopRefundReq 退款参数
     * @return
     */
    public Result<RefundOrderResBO> refundAll(UmsShopRefundReq umsShopRefundReq, RefundOrderBO refundOrderBO, UmsShopProperties umsShopProperties, String url) {
        Result<RefundOrderResBO> result = this.doRefund(umsShopRefundReq, umsShopProperties, url);
        if (result.getRet() != 0) {
            log.error("整单退款失败:{}", result);
            return result;
        }
        if (result.getData() != null && result.getData().getRefundInvoiceAmount() != null) {
            // 实际退款的金额
            PaymentRefundFlow updateRefundFlow = new PaymentRefundFlow();
            updateRefundFlow.setAmount(result.getData().getRefundInvoiceAmount());
            updateRefundFlow.setRefundChannelDiscount(Integer.parseInt(umsShopRefundReq.getRefundAmount()) - result.getData().getRefundInvoiceAmount());
            QueryWrapper<PaymentRefundFlow> conditions = new QueryWrapper<>();
            conditions.eq("flow_id", umsShopRefundReq.getRefundOrderId());
            conditions.eq("user_id", refundOrderBO.getUid());
            paymentRefundFlowMapper.update(updateRefundFlow, conditions);
            result.getData().setRefundInvoiceAmount(0);// 设置实付金额=0，不再做更新
        }
        return result;
    }

    /**
     * 执行退款操作
     *
     * @param umsShopRefundOrderReq 退款参数
     * @return
     */
    public Result<RefundOrderResBO> doRefund(UmsShopRefundReq umsShopRefundOrderReq, UmsShopProperties umsShopProperties, String refundUrl) {
        log.info("ums_shop_refund_url:{}, params:{}", refundUrl, JsonUtil.toJsonString(umsShopRefundOrderReq));
        Result<RefundOrderResBO> result = new Result<>();
        try {
            final UmpShopRefundRes refundOrderResult = new UmsShopHttpUtils<UmpShopRefundRes>(umsShopProperties, refundUrl).doPostToken(JsonUtil.toJsonString(umsShopRefundOrderReq), UmpShopRefundRes.class);
            log.info("银联新购物车订单退款返回:{}", JsonUtil.toJsonString(refundOrderResult));
            result.setRet(refundOrderResult.isOK() ? 0 : 1);
            result.setMsg(refundOrderResult.getRespDesc());
            if (refundOrderResult.getRefundInvoiceAmount() != null && refundOrderResult.getRefundInvoiceAmount() != 0
                    && !refundOrderResult.getRefundInvoiceAmount().equals(refundOrderResult.getRefundAmount())) {
                RefundOrderResBO refundOrderResBO = new RefundOrderResBO();
                // 实付部分退款金额
                refundOrderResBO.setRefundInvoiceAmount(refundOrderResult.getRefundInvoiceAmount());
                result.setData(refundOrderResBO);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("退款失败");
        }
        return result;
    }
}
